package org.myspringframework.beans.factory.config;


import lombok.Data;
import org.myspringframework.beans.BeansException;
import org.myspringframework.beans.factory.ObjectFactory;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Data
//保存单例bean,保存disposableBeans
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    /**
     * 空对象，用于ConcurrentHashMap(不允许存放null为key)
     */
    protected static final Object NULL_OBJECT = new Object();

    //一级缓存，存放完整的单例Bean， key是Bean的名称，value是完整的单例实例对象
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    //二级缓存，存放提前暴露的bean， key是Bean的名称，value是不完整的单例对象，也就是还没有初始化完毕。
    private Map<String, Object> earlySingletonObjects = new ConcurrentHashMap();
    //三级缓存，存放ObjectFactory单例工厂，  key是Bean的名称，value是单例工厂，用于创建key所对应的Bean对象。
    private Map<String, ObjectFactory<?>> singletonFactories = new HashMap();
    //存放正在创建的Bean的名称，创建完成后，从这个集合中删除。
    private Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap());


    //存放DisposableBean
    private final Map<String, DisposableBean> disposableBeans = new ConcurrentHashMap<>();

    //获取单例Bean
    @Override
    public Object getSingleton(String beanName) {
        //从缓存中获取单例bean
        return getSingleton(beanName,true);
    }


    //解决循环依赖的关键！从缓存中获取单例bean
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName); //先检查单例缓存池有没有这个对象,一级缓存,有就直接返回
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 是否正在创建,没有正在创建的话就返回
            singletonObject = this.earlySingletonObjects.get(beanName); // 查看是否有缓存,二级缓存,早期单例池,有也直接返回
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this.singletonObjects) {
                    singletonObject = this.singletonObjects.get(beanName); // 单例模式的双检,加锁之后再查一次一级缓存
                    if (singletonObject == null) { // 经过双检,一级缓存确实没有这个bean
                        singletonObject = this.earlySingletonObjects.get(beanName); // 单例模式的双检,加锁之后再查一次二级缓存
                        if (singletonObject == null) {// 经过双检,二级缓存确实没有这个bean
                            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);//三级缓存,获取beanName对应的单例工厂
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();//通过工厂创建一个早期bean对象(不是完整的)
                                this.earlySingletonObjects.put(beanName, singletonObject); // 放入二级缓存
                                this.singletonFactories.remove(beanName); // 移除三级缓存
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }

    //标记当前正在创建的bean,通过objectFactory获取singletonBean
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory){
        synchronized(this.singletonObjects){
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject==null){
                //标记当前bean正在创建
                singletonsCurrentlyInCreation.add(beanName);
                boolean newSingleton=false;
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
                //删除正在创建的标识
                singletonsCurrentlyInCreation.remove(beanName);
                if (newSingleton){
                    ////将实例化完成后的单例bean添加到一级缓存
                    this.addSingleton(beanName,singletonObject);
                }
            }
            return singletonObject;
        }
    }

    //将创建该Bean的object工厂放入到singletonFactories二级缓存中
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized(this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
            }

        }
    }

    //添加单例Bean到一级缓存
    public void addSingleton(String beanName, Object singletonObject) {
        synchronized(this.singletonObjects) {
            //添加到一级缓存
            this.singletonObjects.put(beanName, singletonObject);
            //删除二级缓存
            this.earlySingletonObjects.remove(beanName);
            //删除三级缓存
            this.singletonFactories.remove(beanName);
        }
    }

    //注册disposavleBean
    public void registerDisposableBean(String beanName, DisposableBean bean) {
        disposableBeans.put(beanName, bean);
    }

    //执行destroy并销毁所有disposableBean
    public void destroySingletons() {
        Set<String> keySet = this.disposableBeans.keySet();
        Object[] disposableBeanNames = keySet.toArray();

        for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
            Object beanName = disposableBeanNames[i];
            DisposableBean disposableBean = disposableBeans.remove(beanName);
            try {
                //执行disposableBean的销毁方法
                disposableBean.destroy();
            } catch (Exception e) {
                throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
            }
        }
    }

    public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }
}